package com.lxg.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;

/**
 * @author 陆小根
 * date: 2022/04/21
 * Description:
 */

@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {

  private final MyUserDetailsService myUserDetailsService;

  @Autowired
  public WebSecurityConfigurer(MyUserDetailsService userDetailsService) {
    this.myUserDetailsService = userDetailsService;
  }

  //  @Bean
//  public UserDetailsService userDetailsService() {
//    InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
//    userDetailsManager.createUser(User.withUsername("root").password("{noop}123").roles("admin").build());
//    return userDetailsManager;
//  }


  // springboot 对 security 默认配置中 在工厂中默认创建 AuthenticationManager
//  @Autowired
//  public void initialize(AuthenticationManagerBuilder builder) throws Exception {
//    System.out.println("SpringBoot 默认配置:" + builder);
//    InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();
//    userDetailsService.createUser(User.withUsername("root").password("{noop}123").roles("admin").build()); // {noop} 明文密码
//    builder.userDetailsService(userDetailsService);
//  }

  //   自定义AuthenticationManager  推荐使用 这种  自定义方式
  @Override
  public void configure(AuthenticationManagerBuilder builder) throws Exception {
    System.out.println("自定义AuthenticationManager:" + builder);
    builder.userDetailsService(myUserDetailsService);
  }

  // 作用：用来将自定义AuthenticationManager在工厂中进行暴露，可以在任何位置注入
  @Override
  @Bean
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            // 放行资源写在任何请求前面
            .mvcMatchers("/login.html").permitAll()
            .mvcMatchers("/index").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin() // 表单认证
            .loginPage("/login.html") // 指定默认的登录页面   注意：一旦自定义登录页面以后必须指定登录的url
            .loginProcessingUrl("/doLogin") // 指定处理登录请求 url
            .usernameParameter("uname")
            .passwordParameter("passwd")
            //.successForwardUrl("/index") // 认证成功 forward 跳转路径    始终在认证成功之后跳转到指定请求
            //.defaultSuccessUrl("/index", true) // 认证成功 redirect 之后的跳转   注意：根据上一保存请求进行成功跳转
            .successHandler(new MyAuthenticationSuccessHandler()) // 认证成功时处理 前后端分离解决方案
            //.failureForwardUrl("/login.html") // 认证失败之后 forward 跳转
            //.failureUrl("/login.html") // 默认情况下 认证失败之后 redirect 跳转
            .failureHandler(new MyAuthenticationFailureHandler()) // 用来自定义认证失败之后处理  前后端分离解决方案
            .and()
            .logout()
            //.logoutUrl("/logout") // 指定注销登录 url  默认请求方式：GET
            .logoutRequestMatcher(new OrRequestMatcher(
                    new AntPathRequestMatcher("/aa", "GET"),
                    new AntPathRequestMatcher("/bb", "POST")
            ))
            .invalidateHttpSession(true) // 默认 会话失效
            .clearAuthentication(true) // 默认 清除认证标记
            //.logoutSuccessUrl("/login.html") // 默认 注销登录 成功之后跳转页面
            .logoutSuccessHandler(new MyLogoutSuccessHandler())  // 注销成功之后处理 前后端分离的配置
            .and()
            .csrf().disable(); // 禁止 csrf 跨站请求保护
    ;
  }
}
